<?php

/**
 * Description of database
 *
 * @author GHoogendoorn
 * @version 0.1
 *
 * Version history:
 * 0.1  GHoogendoorn    Initial version
 * 0.2  GHoogendoorn    Added create database.
 * 0.3  GHoogendoorn    Rename check functions to dbCheck.. and dbquery ->dbQuery
 * 0.4  GHoogendoorn    Removed Error parent => Now error class var.
 * 0.5  GHoogendoorn    Added result type to fetch classes
 *
 */
require_once 'class/db/db_constants.php';
require_once 'class/db/error.php';

/**
 * Language files
 */
require_once 'defs/lang/nl/error.php';
//require_once CLASS_ERROR;

class Database {
    protected   $connection;         //The MySQL database connection
    private     $query_result;
    private     $query;
    private     $error;

    public function __construct() {
        /**
         * Init error class
         */
        $this->error = new Error();
        
        /* Make connection to database */
        $this->connection = mysql_connect(DB_SERVER, DB_USER, DB_PASS, TRUE /* New link */) or die(mysql_error());
        if (! $this->connectDatabase() ){
          // Check db existance (Firsth time create)
          if ( mysql_errno() == 1049 ){
              if ($this->createDatabase()){

                  // If still error just stop
                  $this->connectDatabase() or die(mysql_error());

              }
          } else {
               die(__FILE__.' '.__LINE__.':'.mysql_error());
          }
        }
        echo "<br />". __FILE__ . ' ' . __LINE__ . ' '. "<strong>OPENED DB #". $this->connection ."</strong><br />";
    }

    /**
     *
     * @return string  '' | mysqlerrno()-mysql error txt [query]
     */
    protected function getDbError(){
        if (mysql_errno()){
            return mysql_errno(). '-'. mysql_error(). " [$query]";
        }
        return '';
    }

    /**
     *
     * The function checks the mysql error.
     *
     * @param string $query
     * @return bool FALSE (Ok) or TRUE The error array is set, and should be checked.
     */
    protected function checkDbErrors($query){
        if (mysql_errno()) {
            switch( mysql_errno()){
                case 1062:
                    $this->error->setError( TXT_ERROR_DUPLICATE_ENTRY );
                    break;

                default:
                    $error = "MySQL error ".mysql_errno().": ".
                        mysql_error()."\n<br>".TXT_ERROR_EXECUTING ."<br>\n$query\n<br>";
                    $this->error->setError($error);
                    break;
            }

            return TRUE;
       }
       return FALSE;
   }
   
   /**
    *
    * @return Bool  True if duplicate error found.
    *               False if no errors are found
    */
   protected function ErrorsFound(){
       if (mysql_errno()) {
            switch( mysql_errno()){
                case 1062:
                    $this->error->setError( TXT_ERROR_DUPLICATE_ENTRY );
                    break;

                default:
                    $error = "MySQL error ".mysql_errno().": ".
                        mysql_error()."\n<br>".TXT_ERROR_EXECUTING ."<br>\n$this->query\n<br>";
                    echo __FILE__.__LINE__. $error;
                    throw new Exception($error);
                    
                    break;
            }

            return TRUE;
       }
       return FALSE;
   }

   /**
    * dbQuery - Performs the given query on the database and
    * returns the result, which may be false, true or a
    * resource identifier.
    * 
    * @todo should be protected: Currently called from admin->a.o.
    * @param string $query
    * @return bool TRUE if Ok | FALSE check error array
    * 
    * 
    */
   public function dbQuery($query){
       if( $this->isMySqlResource($this->connection)){
            $this->query_result = mysql_query($query, $this->connection);
            return TRUE;
       }
       return FALSE;
   }
   
   /**
    * function wil execute the $query.
    * if an error is found the throw new Exception is used...
    * 
    * @param type $query 
    */
   protected function query( $query ){
       $this->query = $query;
        
            
       if ( !$this->isMySqlResource($this->connection) ){
           $error = $this->error->getErrorArray();
           throw new Exception ($error[0] );
       }
       $this->query_result = mysql_query($query, $this->connection);
            
       if ($this->checkDbErrors($query)){
           
           $error = $this->error->getErrorArray();
           
           if ( $this->isDuplicateEntry()){
               throw new Exception($error[0], E_WARNING);
           }

           throw new Exception($error[0]);
       }
   }

   /**
     *
     * @param array $data_array The result from a mysql_fetch_array()
     * @return array the modified input array
     */
    protected function dbOutArray($data_array){

        foreach( $data_array as $field => $value ){
            if( is_numeric($value)){
                continue;
            } else if (is_string($value)){
                $data_array[$field] = $this->dbOutString($value);
            }
        }
        return $data_array;
    }


   /**
    * Get the single results from the database
    * This function also removes the database escapes.
    * 
    * This function uses the throw error handling mechanism.
    *
    * @return array The array contains the elements of mysql_fetch_array
    * 
    *
    */
    protected function fetchArray( $result_type = MYSQL_ASSOC){

        if (!$this->isMySqlResource($this->query_result)){
            $err = $this->error->getErrorArray();
            throw new Exception($err[0]);
        }
        //TODO: add error check.	
        $data_array = mysql_fetch_array($this->query_result, $result_type);


        
        
        if(!mysql_errno() && is_array($data_array) ) {
            if ($this->dbNumRows() > 0) {
                $data_array = $this->dbOutArray($data_array);
            }
            
        } else {
            throw new Exception($this->getDbError());
        }
        return $data_array;
    }
    
    /**
    * Get the single results from the database
    * This function also removes the database escapes.
    *
    * @return array The array contains the elements of mysql_fetch_array
    * 
    * @return FALSE No data was found.
    */
    protected function dbFetchArray($result_type=MYSQL_ASSOC){

        if (!$this->isMySqlResource($this->query_result)){
            return FALSE;
        }
        //TODO: add error check.	
        $data_array = mysql_fetch_array($this->query_result, $result_type);

        if ($data_array === FALSE){
            return FALSE;
        }

        if(!mysql_errno()){
            $data_array = $this->dbOutArray($data_array);
        }
        return $data_array;
    }

    protected function dbNumRows(){
        if ($this->isMySqlResource($this->query_result)){
            return mysql_num_rows($this->query_result);
        } else {
            return FALSE;
        }
    }

    /**
    * Get multiple results from the database
    * This function also removes the database escapes.
    *
    * This function uses the throw error handling mechanism.

    * @return array The array contains an array with the row elements
    *
    * @return FALSE No succesfull query was found.
    */
    protected function fetchAll($result_type=MYSQL_ASSOC){

        if (!$this->isMySqlResource($this->query_result)){
            $err = $this->error->getErrorArray();
            throw new Exception($err[0]);
        }
        $return_array = array();

        while ($row = mysql_fetch_array( $this->query_result, $result_type ) ) {
           $return_array[] = $this->dbOutArray($row);
        }
        return $return_array;
    }
    
    /**
    * Get multiple results from the database
    * This function also removes the database escapes.
    *
    * @return array The array contains an array with the row elements
    *
    * @return FALSE No succesfull query was found.
    */
    protected function dbFetchAll($result_type = MYSQL_ASSOC){

        if (!is_resource($this->query_result)){
            echo "<BR />".__FILE__.__LINE__." NO RESOURCE FOUND<br />";
            return FALSE;
        }
        $return_array = array();

        while ($row = mysql_fetch_array( $this->query_result, $result_type ) ) {
           $return_array[] = $this->dbOutArray($row);
        }
        return $return_array;
    }

   /**
    *
    * @param string $table MySql table name
    * @return bool TRUE if exists | False if not exists
    */
   protected function dbTableExists($table){
        $query = 'DESC `'. $table.'`';
        $result = $this->dbQuery($query);
        if (mysql_errno()==1146){
            return FALSE;
        }
        return TRUE;
    }

    /**
     * The function escapes a string.
     *  This function should be called before storage
     *  in the database.
     *
     * @param string $string
     * @return string
     */
    protected function dbInString($string) {

        if (function_exists('mysql_real_escape_string')) {
            return mysql_real_escape_string($string, $this->connection);
          
        } elseif (function_exists('mysql_escape_string')) {
          return mysql_escape_string($string);
        
        }

        return addslashes($string);
    }

    /**
     * The function removes the escapes from a database returned string.
     *  This function should be called after the database query.
     *
     * @param string $string
     * @return string
     */
    protected function dbOutString($string) {
        if (is_string($string)) {
          return trim(stripslashes($string));
        }
    }

    /**
     * Just reset the query resource link
     * 
     */
    protected function dbReset(){
        $this->query_result = '';
    }
    
    /**
     *
     * Check database textfield.
     * @param type $text
     * @param type $len
     * @return type 
     */
    protected function dbCheckText($text, $len, $empty=FALSE){
        if ( !$empty && empty($text) ){
            $this->error->setError( TXT_ERROR_EMPTY_VAR );
            return FALSE;
        }
        
        if (    (!is_string($text))     ||
                (strlen($text) > $len )) {
            
            $this->error->setError( TXT_ERROR_INVALID_TEXT_LEN );
            return FALSE;
        }
        return TRUE;
    }

    /**
     *
     * Check database textfield.
     * Function uses throw errors
     * 
     * @param type $text
     * @param type $len
     * 
     * Exception is thrown if error found.
     */
    protected function checkText($text, $len, $empty=FALSE){
        if ( !$empty && empty($text) ){
            throw new Exception( TXT_ERROR_EMPTY_VAR );
        }
        
        if (    (!is_string($text))     ||
                (strlen($text) > $len )) {
            
            throw new Exception( TXT_ERROR_INVALID_TEXT_LEN );
        }
    }

    
    /**
     *
     * @param int $id A database Id.
     * @param string $field Datase field name
     * @return bool TRUE (ok) or FALSE  The error array is set, 
     *                                  and should be checked
     */
    protected function dbCheckId($id, $field){
         if ( !is_numeric($id)){
            $this->error->setError( TXT_ERROR_WRONG_VAR_TYPE . " [$id] ". $field);
            return FALSE;
        }
        return TRUE;

    }
    
    /**
     *
     * @param int $id A database Id.
     * @param string $field Datase field name
     * 
     * Exception is thrown if error found.
     */
    protected function checkId($id, $field){
        
         if ( !is_numeric($id)){
             throw new Exception( TXT_ERROR_INVALID_TYPE . " [$id] -". $field );
        }
    }
    
    /**
     *
     * checkDate()
     * Check the date formatted field
     * 
     * @param String $date (FormatYYYY-MM-DD)
     * @param Bool $empty if date may be empty set to TRUE
     *
     */
    protected function checkDate( $date, $empty = FALSE){
        if ( ($empty == FALSE ) && empty($date) ){
            throw new Exception(TXT_ERROR_EMPTY_VAR.'['. TXT_DATE.']');
            
        } else if (empty($date)){
            /** Dont check **/
            return;
        }
        
        
        if (strlen(trim($date)) !== DB_DATE_STRLEN ){
            
            throw new Exception(TXT_ERROR_INVALID_DATE_LEN);
        }
        $date_array = explode('-', $date);
        
        if( 
            ( $date_array == FALSE )            ||  // No delimiter found  
            ( strlen($date_array[1]) !== 2 )    ||  //month
            ( strlen($date_array[2]) !== 2  )       //day
        ){
            throw new Exception(TXT_ERROR_INVALID_DATE_FORMAT . "$date");
        }
        // year
        $this->checkYear($date_array[0]);
    }
    
    
    /**
     * 
     * checkYear($year)
     *
     * @param String $year 4 digit input year if empty de current year is returned
     * @return String 4 digit year
     * 
     */
    protected function checkYear( $year ){
        if ( empty($year)) return date('Y');
        
        if ( strlen( $year) !== DB_LEN_GROUP_YEAR){
            throw new Exception ( TXT_ERROR_INVALID_YEAR_LEN );
        }
        
        if (!is_numeric($year)){
            throw new Exception(TXT_ERROR_INVALID_YEAR_FORMAT . " $year");
        }
        
        return $year;
    }
    
    
    protected function checkNumber( $number, $field, $max='', $min=''){
        if( !is_numeric($number)){
            throw new Exception( TXT_ERROR_WRONG_VAR_TYPE . " [$field]");
        }
        
        if ( (!empty($max) && ($number > $max) ) ||
             (!(strlen($min)==0) && ($number < $min))
           ){
                // Error
                throw new Exception( TXT_ERROR_INVALID_TEXT_LEN );
        }
    }
    /**
     *
     * @return int Id generated by the last insert.
     * 
     */
    protected function dbGetInsertedId(){
        return  mysql_insert_id($this->connection);
    }
    
    /**
     *
     * @param resource $res The resource that should be checked
     * @return bool TRUE if $res is mysql resource | FALSE any other case
     * (check error array)
     */
    private function isMySqlResource($res){
        $res_type = is_resource($res) ? get_resource_type($res) : gettype($res);

        if (strpos($res_type, 'mysql') === FALSE)
        {
            $this->error->setError( TXT_ERROR_INVALID_RESOURCE .$res_type);
            return FALSE;
        }
        return TRUE;
    }

    private function connectDatabase(){
        return mysql_select_db(DB_NAME, $this->connection);
    }

    private function createDatabase(){
        $query = "CREATE DATABASE ". DB_NAME;
        return $this->dbQuery($query);
    }
    
    private function isDuplicateEntry(){
        return ((mysql_errno() == 1062 ) ? TRUE : FALSE);
    }
    
    public function __destruct(){

        echo "<br />". __FILE__ . ' ' . __LINE__ . ' '. "<strong>CLOSE DB #". $this->connection ."</strong><br />";
        mysql_close( $this->connection );

    }
}
?>
